package br.edu.delta.util;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.Normalizer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>
 * <b>Title:</b> Util
 * </p>
 * 
 * <p>
 * <b>Description:</b> Util
 * </p>
 * 
 * <p>
 * <b>Company: </b>
 * </p>
 * 
 * @author Denis
 * 
 * @version 1.0.0
 */
public class Util {

	/** Atributo STRING_VAZIA. */
	private static final String STRING_VAZIA = "";

	/** Atributo LETRAS_COM_ACENTUACAO. */
	public static final String LETRAS_COM_ACENTUACAO = "ÁÀÃÂÄÉÈÊËÍÌÏÎÓÒÕÔÖÚÙÛÜÇÑÝŸáàãâäéèêëíìïîóòõôöúùûüçñýÿ";

	/** Atributo LETRAS_SEM_ACENTUACAO. */
	public static final String LETRAS_SEM_ACENTUACAO = "AAAAAEEEEIIIIOOOOOUUUUCNYYaaaaaeeeeiiiiooooouuuucnyy";

	/**
	 * Método responsável por verificar se um objeto é nulo
	 * 
	 * @author Denis
	 * 
	 * @param objeto
	 * @return
	 */
	public static Boolean isNull(final Object objeto) {

		return ( objeto == null ) ? Boolean.TRUE : Boolean.FALSE;
	}

	/**
	 * Método responsável por verificar se um objeto do tipo String é nulo;
	 * 
	 * @author Denis
	 * 
	 * @param str
	 * @return
	 */
	public static Boolean isEmptyString(final String str) {

		return ( !Util.isNull(str) && str.length() == 0 ) ? Boolean.TRUE : Boolean.FALSE;
	}

	/**
	 * Método responsável por verificar se um objeto é nulo ou vazio;
	 * 
	 * @author Denis
	 * 
	 * @param obj
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static boolean isNullOuVazio(final Object obj) {

		if (Util.isNull(obj)) {

			return true;

		} else if (obj instanceof Collection) {

			return ( (Collection) obj ).isEmpty();

		} else if (obj instanceof String) {

			return ( (String) obj ).trim().equals(Util.STRING_VAZIA);

		} else if (obj instanceof Integer) {

			return ( (Integer) obj ).intValue() == 0;
		}

		return false;
	}

	/**
	 * Método responsável por remover acentos de uma String
	 * 
	 * @author Denis
	 * 
	 * @param string
	 * @return
	 */
	public static String removeAcentos(final String string) {

		return Normalizer.normalize(string.trim(), Normalizer.Form.NFD).replaceAll("[^\\p{ASCII}]", Util.STRING_VAZIA);
	}

	// public static String pesquisaPorNome(String nomeParametroPesquisa, String campoBanco) {
	//
	// StringBuilder hql = new StringBuilder();
	// // String nomeModificado = WILDCARD +
	// // translate(nomeParametroPesquisa.trim().toUpperCase()) + WILDCARD;
	// String nomeModificado = PERCENTUAL + removeAcentos(nomeParametroPesquisa.trim().toUpperCase()) + PERCENTUAL;
	// hql.append(" AND TRANSLATE(UPPER(" + campoBanco + "), '" + LETRAS_COM_ACENTUACAO + "', '" + LETRAS_SEM_ACENTUACAO + "') like '" + nomeModificado + "'");
	// return hql.toString();
	// }

	/*
	 * public static String formatData(Date data, String pFormato){ SimpleDateFormat sdate = new SimpleDateFormat(pFormato); return sdate.format(data); }
	 */

	/**
	 * Método responsável por formatar data pela mascara informada
	 * 
	 * @author Denis
	 * 
	 * @param data
	 * @param pFormato
	 * @return
	 */
	public static String formatData(final Date data, final String pFormato) {

		final SimpleDateFormat sdate = new SimpleDateFormat(pFormato);

		return sdate.format(data);
	}

	/**
	 * Método responsável por retornar a hora no formato "dd/MM/yyyy HH:MM"
	 * 
	 * @author Denis
	 * 
	 * @param data
	 * @return
	 */
	public static String formatDataHora(final Date data) {

		final SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:MM");

		return sdf.format(data);
	}

	/**
	 * Método responsável por inserir zeros a esquerda de uma String
	 * 
	 * @author Denis
	 * 
	 * @param input
	 * @param padding
	 * @param length
	 * @return
	 */
	public static String inserirZerosAEsquerda(final String input, final char padding, final int length) {

		String output = Util.STRING_VAZIA;

		if (input != null) {

			output = input;

		}

		if (output.length() >= length) {

			return output;

		} else {

			final StringBuffer result = new StringBuffer();

			final int numChars = length - output.length();

			for (int i = 0; i < numChars; i++) {

				result.append(padding);

			}

			result.append(output);

			return result.toString();

		}

	}

	/**
	 * Método responsável por inserir mascara de cpf
	 * 
	 * @author Denis
	 * 
	 * @param cpf
	 * @return
	 */
	public static String formataCPF(final Long cpf) {

		String cpfString = Util.inserirZerosAEsquerda(Long.toString(cpf), '0', 11);

		if (cpfString != null) {

			// cpfString = cpfString.substring(0, 9) + "-" +
			// cpfString.substring(9, 11);
			cpfString = cpfString.substring(0, 3) + "." + cpfString.substring(3, 6) + "." + cpfString.substring(6, 9) + "-" + cpfString.substring(9, 11);

		}

		return cpfString;
	}

	/**
	 * Método responsável por inserir mascara de cnpj
	 * 
	 * @author Denis
	 * 
	 * @param pCnpj
	 * @return
	 */
	public static String formataCnpj(final Long pCnpj) {

		String cnpjString = Util.inserirZerosAEsquerda(Long.toString(pCnpj), '0', 14);

		if (!Util.isNullOuVazio(cnpjString)) {

			cnpjString = cnpjString.substring(0, 2) + "." + cnpjString.substring(2, 5) + "." + cnpjString.substring(5, 8) + "/" + cnpjString.substring(8, 12) + "-" + cnpjString.substring(12, 14);
		}

		return cnpjString;
	}

	/**
	 * Metodo valida se determinado nome esta de acordo com o padrao da expressao regular
	 * 
	 * @param pExpressaoRegular
	 * @param pNome
	 * @return boolean
	 */
	public static boolean validarNomePorExpressaoRegular(final String pExpressaoRegular, final String pNome) {

		// Obtem expressao regular informada
		final Pattern pattern = Pattern.compile(pExpressaoRegular);
		// Obtem o nome informado
		final Matcher matcher = pattern.matcher(pNome);
		// Verifica se o nome informado esta de acordo com expressao regular
		if (matcher.find()) {
			// Nome e valido segundo a expressao regular
			return true;
		} else {
			// Nome nao e valido segundo a expressao regular
			return false;
		}
	}

	public static String formataCodigo(final Integer codigo) {

		final String codigoFormatado = Util.inserirZerosAEsquerda(Integer.toString(codigo), '0', 4);
		if (codigoFormatado != null) {
			return codigoFormatado;
		} else {
			return Util.STRING_VAZIA;
		}

	}

	/**
	 * Valida CNPJ do usuário.
	 * 
	 * @param cnpj
	 *            String valor com 14 dígitos
	 */
	public static Boolean validaCNPJ(final String cnpj) {

		if (cnpj == null || cnpj.length() != 14) {
			return false;
		}

		try {
			Long.parseLong(cnpj);
		} catch (final NumberFormatException e) { // CNPJ não possui somente números
			return false;
		}

		int soma = 0;
		String cnpj_calc = cnpj.substring(0, 12);

		final char chr_cnpj[] = cnpj.toCharArray();

		for (int i = 0; i < 4; i++) {
			if (chr_cnpj[i] - 48 >= 0 && chr_cnpj[i] - 48 <= 9) {
				soma += ( chr_cnpj[i] - 48 ) * ( 6 - ( i + 1 ) );
			}
		}

		for (int i = 0; i < 8; i++) {
			if (chr_cnpj[i + 4] - 48 >= 0 && chr_cnpj[i + 4] - 48 <= 9) {
				soma += ( chr_cnpj[i + 4] - 48 ) * ( 10 - ( i + 1 ) );
			}
		}

		int dig = 11 - soma % 11;
		cnpj_calc = ( new StringBuilder(String.valueOf(cnpj_calc)) ).append(dig != 10 && dig != 11 ? Integer.toString(dig) : "0").toString();
		soma = 0;

		for (int i = 0; i < 5; i++) {
			if (chr_cnpj[i] - 48 >= 0 && chr_cnpj[i] - 48 <= 9) {
				soma += ( chr_cnpj[i] - 48 ) * ( 7 - ( i + 1 ) );
			}
		}

		for (int i = 0; i < 8; i++) {
			if (chr_cnpj[i + 5] - 48 >= 0 && chr_cnpj[i + 5] - 48 <= 9) {
				soma += ( chr_cnpj[i + 5] - 48 ) * ( 10 - ( i + 1 ) );
			}
		}

		dig = 11 - soma % 11;
		cnpj_calc = ( new StringBuilder(String.valueOf(cnpj_calc)) ).append(dig != 10 && dig != 11 ? Integer.toString(dig) : "0").toString();

		if (!cnpj.equals(cnpj_calc) || cnpj.equals("00000000000000")) {
			// JsfUtil.addErrorMessage("CNPJ Inválido!");
			return false;
		}

		return true;
	}

	public static String convertStringToMD5(final String input) {

		String md5 = null;

		if (null == input) {
			return null;
		}

		try {

			// Create MessageDigest object for MD5
			final MessageDigest digest = MessageDigest.getInstance("MD5");

			// Update input string in message digest
			digest.update(input.getBytes(), 0, input.length());

			// Converts message digest value in base 16 (hex)
			md5 = new BigInteger(1, digest.digest()).toString(64);

		} catch (final NoSuchAlgorithmException e) {

			e.printStackTrace();
		}
		return md5;
	}

	public static String formataLista(final List<String> lista) {

		String r = Util.STRING_VAZIA;
		if (lista.size() >= 1) {
			r += lista.get(0);
			if (lista.size() > 1) {
				for (int i = 1; i < ( lista.size() - 1 ); i++) {
					r += ", " + lista.get(i);
				}
				r += " e " + lista.get(lista.size() - 1);
			}
		}
		return r;
	}

	/**
	 * Método responsável por formatar a mensagem para ser exibida no p:message do JSF o metódo vai criar um paragrafo para cada "/n" encontrado no parâmetro informado.
	 * 
	 * @param textoASerExibido
	 */
	public static void formatarMensagemDeValidacao(final String textoASerExibido) {

		final String[] vetor = textoASerExibido.split("/n");
		for (int i = 0; i < vetor.length; i++) {
			// JsfUtil.addErrorMessage(vetor[i]);
		}
	}

	public static String calculaTempoEntreDatas(final Date d1, final Date d2) {

		if (!Util.isNullOuVazio(d1) && !Util.isNullOuVazio(d2)) {

			final long segundos = ( d2.getTime() / 1000 ) - ( d1.getTime() / 1000 );
			final long segundo = segundos % 60;
			final long minutos = segundos / 60;
			final long minuto = minutos % 60;
			final long hora = minutos / 60;
			final String hms = String.format("%02d:%02d:%02d", hora, minuto, segundo);
			return hms;

		}

		return Util.STRING_VAZIA;
	}

	public static Date parseDate(final String valor, final String formato) {

		try {
			final SimpleDateFormat formatoData = new SimpleDateFormat(formato);
			return formatoData.parse(valor);
		} catch (final ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public static Date parseDateEng(final String valor) {

		try {
			final DateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
			return format.parse(valor);
		} catch (final ParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static String parseDateToString(final Date vlr, final String formato) {

		final DateFormat format = new SimpleDateFormat(formato);
		return format.format(vlr);
	}

	public static String acrescentaZeroEsquerda(String valor, final int tamanho) {

		while (valor.length() < tamanho) {
			valor = "0" + valor;
		}
		return valor;
	}

	/**
	 * Valida CPF do usuario. Não aceita cpfs padrão, como 11111111111 ou 22222222222
	 * 
	 * @param cpf
	 *            String valor com 11 dígitos
	 */
	public static boolean validaCPF(final String cpf) {

		if (cpf == null || cpf.length() != 11 || Util.isCPFPadrao(cpf)) {
			return false;
		}

		try {
			Long.parseLong(cpf);
		} catch (final NumberFormatException e) { // CPF não possui somente n�meros
			return false;
		}

		if (!Util.calcDigVerif(cpf.substring(0, 9)).equals(cpf.substring(9, 11))) {
			return false;
		}

		return true;
	}

	/**
	 * 
	 * @param cpf
	 *            String valor a ser testado
	 * @return boolean indicando se o usuário entrou com um CPF padrão
	 */
	private static boolean isCPFPadrao(final String cpf) {

		if (cpf.equals("00000000000") || cpf.equals("11111111111") || cpf.equals("22222222222") || cpf.equals("33333333333") || cpf.equals("44444444444") || cpf.equals("55555555555") || cpf.equals("66666666666") || cpf.equals("77777777777") || cpf.equals("88888888888") || cpf.equals("99999999999")) {

			return true;
		}

		return false;
	}

	private static String calcDigVerif(final String num) {

		Integer primDig, segDig;
		int soma = 0, peso = 10;
		for (int i = 0; i < num.length(); i++) {
			soma += Integer.parseInt(num.substring(i, i + 1)) * peso--;
		}

		if (soma % 11 == 0 | soma % 11 == 1) {
			primDig = new Integer(0);
		} else {
			primDig = new Integer(11 - ( soma % 11 ));
		}

		soma = 0;
		peso = 11;
		for (int i = 0; i < num.length(); i++) {
			soma += Integer.parseInt(num.substring(i, i + 1)) * peso--;
		}

		soma += primDig.intValue() * 2;
		if (soma % 11 == 0 | soma % 11 == 1) {
			segDig = new Integer(0);
		} else {
			segDig = new Integer(11 - ( soma % 11 ));
		}

		return primDig.toString() + segDig.toString();
	}

	public static boolean validaDvCaixa(final String conta, final String dv) {

		int peso = 8, soma = 0;

		for (final char c : conta.toCharArray()) {
			final int n = Integer.parseInt(String.valueOf(c));
			soma += n * peso;
			peso--;
			if (peso < 2) {
				peso = 9;
			}
		}

		int modulo = ( soma * 10 ) % 11;

		if (modulo == 10) {
			modulo = 0;
		}

		return ( modulo == Integer.parseInt(dv) ) ? Boolean.TRUE : Boolean.FALSE;
	}

	/**
	 * Método responsável por criptografar uma senha
	 * 
	 * @author Denis
	 * 
	 * @param senha
	 * @return
	 */
	public static String senhaCriptografada(final String senha) {

		// codigo abaixo representa a senha 123
		// a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3

		try {

			MessageDigest md;

			md = MessageDigest.getInstance("SHA-256");

			md.update(senha.getBytes());

			final byte byteData[] = md.digest();

			final StringBuffer sb = new StringBuffer();

			for (final byte b : byteData) {

				sb.append(Integer.toString(( b & 0xff ) + 0x100, 16).substring(1));
			}

			return sb.toString();

		} catch (final NoSuchAlgorithmException e) {

			e.getMessage();

			return null;
		}
	}
}
